import { compareJson } from './compareJson'
import { incrementalUpdateMapJson } from './api'

export function hasChild (data) {
  return data.children?.length
}

/**
 * 生成指定区间内的一个随机数
 * @param {*} min
 * @param {*} max
 * @returns
 */
export function getRandomDigit (min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min
}

/**
 * 生成一个随机id
 * @returns
 */
export function generateRandomId () {
  let randomId = ''
  for (let i = 0; i < 5; i++) {
    const up = String.fromCharCode(65 + Math.floor(Math.random() * 26))
    const low = String.fromCharCode(97 + Math.floor(Math.random() * 26))
    randomId += Math.random() > 0.5 ? up : low
  }
  return randomId + String(Math.random()).substring(2)
}

/**
 * 根据种子和随机字符串生成新的随机字符串
 * @param {*} seed
 * @param {*} randomId
 * @returns
 */
export function transformRandomIdFromSeed (randomId, seed) {
  let newRandomId = ''
  for (let i = 0; i < randomId.length; i++) {
    const str = randomId[i]
    const code = str.charCodeAt()
    if (code >= 48 && code <= 57) {
      newRandomId += String.fromCharCode(((code + seed) % 10) + 48)
    } else {
      if (code >= 65 && code <= 90) {
        newRandomId += String.fromCharCode(((code + seed) % 26) + 65)
      } else if (code >= 97 && code <= 122) {
        newRandomId += String.fromCharCode(((code + seed) % 26) + 97)
      }
    }
  }
  return newRandomId
}

/**
 * 数据设置唯一标识_id
 * @param {*} node
 * @param {*} update
 */
export function setJsonUniqueId (node, update, seed = getRandomDigit(100, 360)) {
  node._id = update ? transformRandomIdFromSeed(node._id, seed) : node._id || generateRandomId()
  if (node.relations?.length) {
    node.relations.forEach(relation => {
      relation.relationId = transformRandomIdFromSeed(relation.relationId, seed)
      relation.sourceInfo.id = transformRandomIdFromSeed(relation.sourceInfo.id, seed)
      relation.targetInfo.id = transformRandomIdFromSeed(relation.targetInfo.id, seed)
    })
  }
  if (node.targetSummarys?.length) {
    node.targetSummarys.forEach(summary => {
      summary.id = transformRandomIdFromSeed(summary.id, seed)
    })
  }
  if (node.outBorder?.id) {
    node.outBorder.id = transformRandomIdFromSeed(node.outBorder.id, seed)
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      setJsonUniqueId(n, update, seed)
    })
  }
}

/**
 * 判断数据是否为空
 * @param {*} data
 * @returns
 */
export function isEmpty (data) {
  return (
    data === null ||
    data === undefined ||
    data === '' ||
    JSON.stringify(data) === '{}' ||
    JSON.stringify(data) === '[]'
  )
}

/**
 *
 * @param {*} nodes
 * @param {*} id
 * @param {*} type 插入为同级节点或者自己节点 brother - 同级节点  child - 子集节点
 * @param {*} insertNode 复制节点的时候需要重新设置每个节点的id
 * @returns
 */
export function insertXmindNode (nodes, id, type, insertNode, pos) {
  let cache = null
  insertNode && setJsonUniqueId(insertNode, true)
  function m (nodes, id, type) {
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i]._id === id) {
        cache = createNodeIntance(undefined, false, pos)
        if (type === 'brother') {
          const prevBrother = nodes[nodes.length - 1]
          const prevBrotherStyle = prevBrother.pos ? null : prevBrother.customStyle
          nodes.push({
            ...cache,
            customStyle: { ...prevBrotherStyle }
          })
        } else if (type === 'child') {
          const brothers = nodes[i].children || []
          const prevBrother = brothers[brothers.length - 1]
          const prevBrotherStyle = prevBrother?.pos ? null : prevBrother?.customStyle
          nodes[i].children = [
            ...(nodes[i].children || []),
            {
              ...(insertNode || cache),
              customStyle: { ...(insertNode?.customStyle || prevBrotherStyle) }
            }
          ]
        }
      }
      if (hasChild(nodes[i])) {
        m(nodes[i].children, id, type)
      }
    }
  }
  m(nodes, id, type)

  return cache
}

/**
 * 批量插入节点
 * @param {*} nodes
 * @param {*} ids
 * @param { String } type 插入为同级节点或者自己节点 brother - 同级节点  child - 子集节点
 */
export function batchInsertXmindNode (nodes, ids, type) {
  const cache = []
  function m (nodes, ids, type) {
    for (let i = 0; i < nodes.length; i++) {
      const idx = ids.findIndex(id => id === nodes[i]._id)
      if (idx > -1) {
        const t = createNodeIntance()
        // 根节点和自由节点不能插入同级节点
        if (type === 'brother' && !nodes[i].isRoot && !nodes[i].pos) {
          const prevBrother = nodes[nodes.length - 1]
          const prevBrotherStyle = prevBrother.pos ? null : prevBrother.customStyle
          nodes.push({
            ...t,
            customStyle: { ...prevBrotherStyle }
          })
          cache.push(t)
          ids.splice(idx, 1)
        } else if (type === 'child') {
          const brothers = nodes[i].children || []
          const prevBrother = brothers[brothers.length - 1]
          const prevBrotherStyle = prevBrother?.pos ? null : prevBrother?.customStyle
          nodes[i].children = [
            ...(nodes[i].children || []),
            { ...t, customStyle: { ...prevBrotherStyle } }
          ]
          cache.push(t)
          ids.splice(idx, 1)
        }

        if (ids.length === 0) return
      }
      if (hasChild(nodes[i])) {
        m(nodes[i].children, ids, type)
      }
    }
  }

  m(nodes, ids, type)

  return cache
}

export function batchReferenceStyle (node, ids, style) {
  const idx = ids.findIndex(id => id === node._id)
  if (idx > -1) {
    node.customStyle = { ...node.customStyle || {}, ...style }
    ids.splice(idx, 1)
    if (ids.length === 0) return
  }
  if (hasChild(node)) {
    for (let i = 0; i < node.children.length; i++) {
      batchReferenceStyle(node.children[i], ids, style)
    }
  }
}

/**
 * 递归遍历节点删除指定的节点
 * @param {*} nodes
 * @param {*} id
 * @param {*} newList 删除后需要插入的元素
 */
export function deleteXmindNode (nodes, id, newList) {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i]._id === id) {
      nodes.splice(i, 1, ...(newList || []))
      break
    }
    if (hasChild(nodes[i])) {
      deleteXmindNode(nodes[i].children, id, newList)
    }
  }
}

/**
* 批量删除节点
* @param {*} nodes
* @param {*} ids
*/
export function batchDeleteXmindNode (nodes, ids) {
  for (let i = 0; i < nodes.length; i++) {
    const idx = ids.findIndex(id => id === nodes[i]._id)
    if (idx > -1) {
      nodes.splice(i, 1)
      ids.splice(idx, 1)
      i--
    } else {
      if (hasChild(nodes[i])) {
        batchDeleteXmindNode(nodes[i].children, ids)
      }
    }
  }
}

/**
 * 上下移节点
 * @param {*} nodes
 * @param {*} id
 * @param {*} arrow up - 上移 down - 下移
 */
export function moveXmindNode (nodes, id, arrow) {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i]._id === id) {
      if (arrow === 'up') {
        if (i !== 0) {
          const tNode = nodes.splice(i, 1)[0]
          nodes.splice(i - 1, 0, tNode)
        }
      } else if (arrow === 'down') {
        if (i !== nodes.length - 1) {
          const tNode = nodes.splice(i, 1)[0]
          nodes.splice(i + 1, 0, tNode)
        }
      }
      break
    }
    if (hasChild(nodes[i])) {
      moveXmindNode(nodes[i].children, id, arrow)
    }
  }
}

/**
 * 剪切拷贝节点
 * @param {*} node
 * @param {*} id
 * @param {*} iscut
 */
export function copyOrCutXmindNode (nodes, node, id, iscut = false) {
  if (node._id === id) {
    const copyNodeInstance = JSON.parse(JSON.stringify(node))
    if (iscut) {
      deleteXmindNode(nodes, id)
    } else {
      copyNodeInstance.relations = null
      copyNodeInstance.isRoot = false
    }
    return copyNodeInstance
  }
  if (hasChild(node)) {
    for (let i = 0; i < node.children.length; i++) {
      const copyNodeInstance = copyOrCutXmindNode(nodes, node.children[i], id, iscut)
      if (copyNodeInstance) {
        return copyNodeInstance
      }
    }
  }
}

/**
 * 收起展开子节点
 * @param {*} node
 * @param {*} id
 * @param { Boolean } expand true - 展开 false - 收起
 */
export function toogleExpandXmindNode (node, id, expand) {
  if (node._id === id) {
    node.expand = expand
    if (!expand) {
      node.childCount = node.children.length
    } else {
      node.childCount = 0
    }
    return
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      toogleExpandXmindNode(n, id, expand)
    })
  }
}

/**
 * 收起展开所有节点
 * @param {*} node
 * @param { Boolean } expand true - 展开 false - 收起
 */
export function expandAllNodes (node, expand) {
  if (!hasChild(node)) {
    node.expand = true
  } else {
    node.expand = expand
    if (!expand) {
      node.childCount = node.children?.length
    } else {
      node.childCount = 0
    }
    node.children.forEach(n => {
      expandAllNodes(n, expand)
    })
  }
}

/**
 * 备份根节点隐藏所有节点属性expand为false的所有子节点
 * @param {*} node
 * @returns
 */
export function backupRootDeleteChild (node) {
  const backupTopics = JSON.parse(JSON.stringify(node))
  const independentTopics = [] // 独立自由主题
  function backup (root) {
    if (!root.expand) (root.children = null)
    if (hasChild(root)) {
      root.children.forEach(n => {
        backup(n)
      })
    }
    if (root.isRoot && hasChild(root)) {
      for (let i = 0; i < root.children.length; i++) {
        const c = root.children[i]
        if (c.pos) {
          independentTopics.push(root.children.splice(i, 1)[0])
          i--
        }
      }
    }
  }
  backup(backupTopics)

  return {
    backupTopics,
    independentTopics
  }
}

/**
 * 左右布局的时候给root按照下标分为左右两个root
 * @param {*} root
 * @param { * } structure 思维导图结构
 */
export function splitLeftRightRoot (root, structure) {
  if (!['org.xmind.ui.map.clockwise', 'org.xmind.ui.timeline.vertical'].includes(structure) || !hasChild(root)) {
    return {
      leftRoot: {},
      rightRoot: root
    }
  }

  if (hasChild(root)) {
    if (root.children.length <= 2) {
      return {
        leftRoot: {},
        rightRoot: root
      }
    }
    const [leftRoot, rightRoot] = [{ ...root, children: [] }, { ...root, children: [] }]
    const len = root.children.length
    const cacheNodes = setRightLeftTopics(root.children)
    for (let i = 0; i < cacheNodes.length; i++) {
      if (rightRoot.children.length + cacheNodes[i].length <= Math.ceil(len / 2)) {
        rightRoot.children.push(...cacheNodes[i])
      } else {
        leftRoot.children.push(...cacheNodes[i])
      }
    }
    return {
      leftRoot,
      rightRoot
    }
  }
}

/**
 * 在两个节点之间有概要关系时，思维导图结构下把有关联的节点放在同一侧
 * @param {*} nodes
 * @returns
 */
function setRightLeftTopics (nodes) {
  const cacheNodes = []
  for (let i = 0; i < nodes.length; i++) {
    const targetSummarys = nodes[i].targetSummarys
    // 节点不存在概要关系
    if (!targetSummarys?.length) {
      cacheNodes.push([nodes[i]])
      continue
    }
    const cache = [nodes[i]]
    _c(cache, targetSummarys, i)
    cacheNodes.push(cache)
  }

  function _c (cache, targetSummarys, i) {
    const maxIdx = Math.max(...targetSummarys.map(o => nodes.findIndex(kk => kk._id === o.id)))
    if (maxIdx > i) {
      const len = maxIdx - i
      const betweenNodes = nodes.splice(i + 1, len)
      cache.push(...betweenNodes)
      for (let k = 0; k < betweenNodes.length; k++) {
        if (betweenNodes[k].targetSummarys?.length) {
          _c(cache, betweenNodes[k].targetSummarys, i)
        }
      }
      i -= len
    }
  }
  return cacheNodes
}

/**
 * 递归树节点找到指定数据更新指定的key值
 * @param { Object } node 节点数据
 * @param { String } id 节点唯一标识
 * @param { String } key 需要更新的节点key字段
 * @param { String } value 更新后的值
 */
export function recursiveTreeValue (node, id, key, value) {
  if (node._id === id) {
    if (key.includes('.')) {
      const keys = key.split('.')
      node[keys[0]][keys[1]] = value
    } else {
      node[key] = value
    }
    return
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      recursiveTreeValue(n, id, key, value)
    })
  }
}

/**
 * 批量节点更新指定样式
 * @param {*} node
 * @param {*} ids
 * @param {*} key
 * @param {*} value
 * @returns
 */
export function bacthUpdateNodeCustomStyle (node, ids, key, value) {
  const idx = ids.findIndex(o => o === node._id)
  if (idx > -1) {
    if (node.customStyle) {
      node.customStyle[key] = value
    } else {
      node.customStyle = {}
      node.customStyle[key] = value
    }
    ids.splice(idx, 1)
    if (!ids.length) return
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      bacthUpdateNodeCustomStyle(n, ids, key, value)
    })
  }
}

/**
 * 全局节点自定义样式更新
 * @param {*} node
 * @param {*} key
 * @param {*} value
 */
export function gloabUpdateNodeCustomStyle (node, key, value) {
  if (node.customStyle) {
    node.customStyle[key] = value
  } else {
    node.customStyle = {}
    node.customStyle[key] = value
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      gloabUpdateNodeCustomStyle(n, key, value)
    })
  }
}

/**
 * 重置整个画布节点样式
 * @param {*} root
 * @param {*} deep
 */
export function resetRootNodeStyle (root) {
  root.customStyle = null
  if (hasChild(root)) {
    for (let k = 0; k < root.children.length; k++) {
      resetRootNodeStyle(root.children[k])
    }
  }
}

/**
 * 批量节点清除自定义样式
 * @param {*} node
 * @param {*} ids
 * @returns
 */
export function batchResetNodeStyle (node, ids) {
  const idx = ids.findIndex(o => o === node._id)
  if (idx > -1) {
    node.customStyle = null
    ids.splice(idx, 1)
    if (!ids.length) return
  }
  if (hasChild(node)) {
    node.children.forEach(n => {
      batchResetNodeStyle(n, ids)
    })
  }
}

/**
 * 根据指定的id展开id所在路径上的所有父级数据
 * @param {*} id
 */
export function unFoldTargetNodePath (data, id) {
  function t (data, id, cache = [], depth = 0) {
    if (data._id === id) return [...cache, data]
    cache = cache.slice(0, depth)
    cache.push(data)
    if (hasChild(data)) {
      for (let i = 0; i < data.children.length; i++) {
        const tt = t(data.children[i], id, cache, depth + 1)
        if (tt && tt[tt.length - 1]._id === id) {
          return tt
        }
      }
    }
  }
  const topics = t(data, id, [], 0)
  if (topics) {
    const tt = topics.slice(0, topics.length - 1)
    let needUpdate = false
    tt.forEach(o => {
      if (!o.expand) {
        needUpdate = true
      }
      o.expand = true
      o.childCount = 0
    })
    return needUpdate
  } else {
    return 'topic is no exist'
  }
}

/**
 * 根据_id获取指定数据
 * @param {*} data
 * @param {*} value
 */
export function getTargetDataById (data, id) {
  if (data._id === id) return data
  if (hasChild(data)) {
    for (let i = 0; i < data.children.length; i++) {
      const d = getTargetDataById(data.children[i], id)
      if (d) return d
    }
  }
}

export function batchRecursiveTreeValue (node, ids, key, value) {
  const idx = ids.findIndex(id => id === node._id)
  if (idx > -1) {
    node[key] = value
    ids.splice(idx, 1)
  }
  if (hasChild(node) && ids.length) {
    node.children.forEach(n => {
      batchRecursiveTreeValue(n, ids, key, value)
    })
  }
}

/**
 * 初始化新增节点的数据信息
 */
export function createNodeIntance (text, isRoot = false, pos) {
  return {
    text: text || 'Main Topic',
    children: null,
    _id: generateRandomId(),
    expand: true,
    childCount: 0,
    isRoot,
    pos
  }
}

const debounceUpdateStorageRoot = debounce((sheets, displaySheet, mindId) => {
  console.log('xmind map has updated.')
  const idx = sheets.findIndex(m => m.id === displaySheet.id)
  const olddata = JSON.parse(window.localStorage.getItem('sheets'))[idx]
  const newdata = sheets[idx]
  window.localStorage.setItem('sheets', JSON.stringify(sheets))
  const delta = compareJson(olddata, newdata)
  delta && incrementalUpdateMapJson(mindId, displaySheet.id, delta)
}, 300)

/**
 * 更新root数据后实时存储数据
 * @param {*} sheets
 * @param {*} displaySheet
 * @param {*} mindId
 */
export function storageRootRelaTime (sheets, displaySheet, mindId) {
  debounceUpdateStorageRoot(sheets, displaySheet, mindId)
}

/**
 * 防抖
 * @param {*} func
 * @param {*} delay
 * @returns
 */
export function debounce (func, delay) {
  let timer = null
  return function () {
    const self = this
    const args = arguments
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(self, args)
    }, delay)
  }
}

/**
 * 计算节点树所有文字个数和节点个数
 */
export function statisticTreeCount (root) {
  let [len, count] = [0, 0]
  function getStatistic (root) {
    const tagLength = (root.tag?.split(';') || [])
      .reduce((prev, cur) => {
        prev += cur.length
        return prev
      }, 0)
    len +=
        (root.text?.length || 0) +
        (root.summary?.length || 0) + tagLength
    count += 1
    if (hasChild(root)) {
      for (let i = 0; i < root.children.length; i++) {
        getStatistic(root.children[i])
      }
    }
  }
  getStatistic(root)
  return {
    len, count
  }
}

/**
 * src to base64
 * @param {*} picsrc
 * @param {*} width
 * @param {*} height
 * @returns
 */
export function imageToBase64 (picsrc, width, height) {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.setAttribute('crossOrigin', 'anonymous')
    img.onload = async () => {
      try {
        const canvas = document.createElement('canvas')
        canvas.width = width || img.width
        canvas.height = height || img.height
        const ctx = canvas.getContext('2d')
        ctx.drawImage(img, 0, 0, width || img.width, height || img.height)
        resolve(canvas.toDataURL())
      } catch (error) {
        reject(error)
      }
    }
    img.onerror = e => {
      reject(e)
    }
    img.src = picsrc
  })
}

/**
 * 节点样式获取
 */
export function getNodeCustomStyle (node) {
  const {
    fontFamily,
    fontSize,
    fontWeight,
    fontStyle,
    textDecoration,
    textDirection,
    textColor,
    strokeColor,
    strokeStyle,
    strokeWidth,
    backgroundColor,
    lineStyle,
    lineWidth,
    lineColor,
    lineEndJoin,
    horizontalOutter,
    shape,
    maxWidth,
    align,
    branch,
    dot
  } = node.customStyle || {}
  return {
    fontFamily,
    fontSize,
    fontWeight,
    fontStyle,
    textDecoration,
    textDirection,
    textColor,
    strokeColor,
    strokeStyle,
    strokeWidth,
    backgroundColor,
    lineStyle,
    lineWidth,
    lineColor,
    lineEndJoin,
    horizontalOutter,
    shape,
    maxWidth,
    align,
    branch,
    dot
  }
}
